package com.yckj.ytracker.api.model;

import com.yckj.ytracker.api.enums.SpanStatus;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author liuwei
 * @version 2017/10/16 上午11:07
 * @description 节点
 * @see
 * @since 1.0
 */
public class Span {
    /**
     * 版本号
     */
    private byte version = 1;
    /**
     * 调用链唯一标识
     */
    private String traceId;
    /**
     * 集群名
     */
    private String clusterName;
    /**
     * 类型
     */
    private String type;
    /**
     * 方法名
     */
    private String funcName = "";
    /**
     * 参数
     */
    private String param = "";
    /**
     * 节点层级关系id
     */
    private String spanId;
    /**
     * 记录span开始的时间
     */
    private long time;
    /**
     * 记录该span所花费的时间
     */
    private long cost;
    /**
     * 父节点
     */
    private Span parentSpan;
    /**
     * 节点状态
     */
    private int state = SpanStatus.OK.getKey();
    /**
     * 序号
     */
    private final AtomicInteger idx;
    /**
     * 自定义数据
     */
    private Map<String, String> attributes;
    /**
     * 本地网络信息
     */
    private Endpoint local;
    /**
     * 远程网络信息
     */
    private Endpoint remote;
    /**
     * 堆栈信息
     */
    private String stack;
    /**
     * 跟节点集群名
     */
    private String rootName;

    public Span() {
        this.idx = new AtomicInteger(0);
        this.local = new Endpoint();
        this.remote = new Endpoint();
        setLocalIp("127.0.0.1");
    }

    public Span(String traceId, String spanId, String clusterName) {
        this.traceId = traceId;
        this.spanId = spanId;
        this.clusterName = clusterName;
        this.idx = new AtomicInteger(0);
        this.local = new Endpoint();
        this.remote = new Endpoint();
        setLocalIp("127.0.0.1");
    }

    public int nextSpanId() {
        return this.idx.incrementAndGet();
    }

    public String putData(String key, String value) {
        if (this.attributes == null) {
            this.attributes = new LinkedHashMap<String, String>();
        }
        return (this.attributes.put(key, value));
    }

    public String nextChildTrackId() {
        return this.spanId + "." + nextSpanId();
    }

    public byte getVersion() {
        return version;
    }

    public void setVersion(byte version) {
        this.version = version;
    }

    public String getClusterName() {
        return clusterName;
    }

    public void setClusterName(String clusterName) {
        this.clusterName = clusterName;
    }

    public void setTraceId(String traceId) {
        this.traceId = traceId;
    }

    public String getTraceId() {
        return traceId;
    }

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }

    public long getCost() {
        return cost;
    }

    public void setCost(long cost) {
        this.cost = cost;
    }

    public Span getParentSpan() {
        return parentSpan;
    }

    public void setParentSpan(Span parentSpan) {
        this.parentSpan = parentSpan;
    }

    public Map<String, String> getAttributes() {
        return attributes;
    }

    public void setAttributes(Map<String, String> attributes) {
        this.attributes = attributes;
    }

    public AtomicInteger getIdx() {
        return idx;
    }

    public String getSpanId() {
        return spanId;
    }

    public void setSpanId(String spanId) {
        this.spanId = spanId;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getFuncName() {
        return funcName;
    }

    public void setFuncName(String funcName) {
        this.funcName = funcName;
    }

    public String getParam() {
        return param;
    }

    public void setParam(String param) {
        this.param = param;
    }

    public Endpoint getLocal() {
        return local;
    }

    public void setLocal(Endpoint local) {
        this.local = local;
    }

    public Endpoint getRemote() {
        return remote;
    }

    public void setRemote(Endpoint remote) {
        this.remote = remote;
    }

    public void setRemoteIpAndPort(String remoteIp, String remotePort) {
        this.remote.setHost(remoteIp);
        this.remote.setPort(remotePort);
    }

    public void setLocalIpAndPort(String localIp, String localPort) {
        this.local.setHost(localIp);
        this.local.setPort(localPort);
    }

    public void setLocalIp(String localIp) {
        this.local.setHost(localIp);
    }

    public void setLocalPort(String localPort) {
        this.local.setPort(localPort);
    }

    public String getStack() {
        return stack;
    }

    public void setStack(String stack) {
        this.stack = stack;
    }

    public String getRootName() {
        return rootName;
    }

    public void setRootName(String rootName) {
        this.rootName = rootName;
    }

    @Override
    public String toString() {
        return "Span{" +
                "version=" + version +
                ", traceId='" + traceId + '\'' +
                ", clusterName='" + clusterName + '\'' +
                ", type='" + type + '\'' +
                ", funcName='" + funcName + '\'' +
                ", param='" + param + '\'' +
                ", spanId='" + spanId + '\'' +
                ", time=" + time +
                ", cost=" + cost +
                ", parentSpan=" + parentSpan +
                ", state=" + state +
                ", idx=" + idx +
                ", attributes=" + attributes +
                ", local=" + local +
                ", remote=" + remote +
                ", stack='" + stack + '\'' +
                ", rootName='" + rootName + '\'' +
                '}';
    }
}
